home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
TPUG - Toronto PET Users Group
/
TPUG Users Group CD
/
TPUG Users Group CD.iso
/
AMIGA
/
AMICUS
/
AMICUS02.ADF
/
Tutorials
/
Gadgets
< prev
next >
Wrap
Text File
|
1989-05-30
|
37KB
|
981 lines
PHUN WITH GADGETS - John T. Draper
----------------------------------
Feel free to distribute this information onto any network. Please check
first to avoid duplication. Would at least like credit for the 20 hours or
so I took in preparing this section.
Gadgets are multi function input "devices" which run under Intuition. There
are four kinds, and two flavors.
The flavors are:
1) System gadgets - Those created for you when you create a window or screen
2) User gadgets - Those gadgets YOU create and use in your program. There
are four kinds of these.
The four kinds are:
1) Boolean Gadgets - Usually "Yes/no" desisions, "On/Off" buttons, and
other related uses. They look like rectangles, with text displayed (Or
rendered), within those rectangles.
2) Proportional Gadgets - Those which look like "Sliders" as displayed in the
"R G B" Controls in the "Preferences" program. I think Amiga should
release the source to Preferences, because It would be a very good
example program.
3) String gadgets - These allow text entry through the Keyboard. Text can be
automatically centered.
4) Integer Gadget - A special form of string gadget that converts numeric
text input into integers.
USING GADGETS
-------------
Each gadget has a data structure "Gadget", which must first be declared and
initialized. There are several ways to do this. The easiest way is to
declare and initialize them like this:
#define BLUE_GADGET 0 /* My own Gadget ID to mean this gadget */
struct Gadget blue_gad = {
NL, 17,112, 150,11, GADGHCOMP, GADGIMMEDIATE | RELVERIFY,
PROPGADGET,(APTR)&b_img, NL,
&btxt, NL,(APTR)&b_prop, BLUE_GADGET, NL
};
#define GREEN_GADGET 1 /* Another personal ID */
struct Gadget green_gad = {
&blue_gad, 17,97, 120,11, GADGHCOMP, GADGIMMEDIATE | RELVERIFY,
PROPGADGET,(APTR)&g_img, NL,
>xt, NL,(APTR)&g_prop, GREEN_GADGET, NL
};
#define RED_GADGET 2 /* And yet another gadget */
struct Gadget red_gad = {
&green_gad, 17,82, 90,11, GADGHCOMP, GADGIMMEDIATE | RELVERIFY,
PROPGADGET,(APTR)&r_img, NL,
&rtxt, NL,(APTR)&r_prop, RED_GADGET, NL
};
#define TEX_GAD 3
struct Gadget tex_gad = {
&red_gad, 10,10, 150,11, GADGHCOMP, STRINGCENTER | LONGINT,
STRGADGET, NL, NL,
NL, NL, (APTR)&TexString, TEX_GAD, NL
};
The #define BLUE_GADGET 0, etc, are my own personal numbers that I want to
use to identify these gadgets in my very own personal way. I am using them
for identification and to take action when the gadget is chosen via a C
"Switch" statement.
Each "Element" in the structures declared above are separated by commas (For
those not familiar with C), and will be explained in detail. In the above
examples are Three Proportional Gadgets, and a Text Gadget. A more detailed
description of each of the gadget fields are listed below. It is pretty well
explained in the Intuition manual. Just a lack of examples showing how to
build and detect them.
-- (NextGadget) First element is the "link" to the next gadget. Last gadget
has a Null (NL) for a link. Note, the last gadget is on the top. The
LAST Gadget should be set to NULL (NL).
-- (LeftEdge, TopEdge) - Specifies the LOCATION of the gadget relative to the
window or screen, in the above example, "tex_gad.LeftEdge" has the
value of 10. The last gadget has LeftEdge = 17, TopEdge = 112 as shown
above.
-- (Width, Height) - Specifies the Width and the height of the gadget select
box. In the above example, the height remained the same, and the Width
progressively got smaller. Width = 150, Height = 11 on the last one,
then Width = 120, then eventually 90, See above.
-- (Flags) - Flags that you share with Intuition.to describe the appearance
and behavior of the gadget. GADGHCOMP is a flag that complements all
of the bits contained within the gadget's select box.
-- (Activation) - Other flags that are used to activate certain features of
the gadget. GADGIMMEDIATE | RELVERIFY mean that we set BOTH those "Bits".
-- (GadgetType) - Describes the type of gadget. In the example above,
STRGADGET is one of the four types of gadgets that describe "string" or
"Text".
-- (GadgetRender) - Points to an intuiImage. This is what gets written onto
screen or window as the gadget. In the case where we use the proportional
gadget, we supply the address of the Image Structure without initializing
it. It then gets rendered as a rectangle.
-- (SelectRender) - In this example, we put a NULL (NL) in this field. If
we wanted, we could put in another image. This image would be displayed
during highlighting (When mouse button is pressed in the gadget's select
box).
-- (GadgetText) - A pointer to an "Intuitext" structure that describes any
text that might be rendered when the gadget is rendered.
-- (MutualExclude) - In this example, we place a NULL (NL). There are 32
bits that can be used to "Turn off" other gadgets if this gadget gets
selected.
-- (SpecialInfo) - A pointer to more information about proportional (PropInfo)
and text (StringInfo).
gadgets.
-- (GadgetID) - User definable ID Field. It can be used to identify the
gadget from the gadget pointer. I use it as an argument to the
"switch" statement, because using an address (Or any large number) as
arguments to the "switch" statement will cause the system to crash.
It's a bug in the Lattice C compiler.
-- (UserData) - A pointer to data that can be of any user definable
structure or data.
There are other structures needed for gadgets which are "SpecialInfo" types
of structures. They are: PropInfo, and StringInfo structures. These describe
in detail more information on Proportional structures and Text structures.
Addresses of these structures will be put in the "SpecialInfo" field of the
gadget structure. For instance, in the example above where the gadgets are
declared and initialized, (APTR)&r_img is used in the "red_gad" declaration.
Where "r_img" is declared as follows:
struct Image r_img, g_img, b_img;
In this particular example, these are Images used by Intuition. Sometimes
YOU have to declare your own image. Other times, such as in the case above,
Intuition initializes these images. On first reading of the Intuition
manual, it is not evident that These are initialized.
PropInfo Structure:
-------------------
A PropInfo structure contains specific information about a proportional
gadget. Such as a slider arm, or a volume control.
-- (flags) - A set of flags like:
AUTOKNOB - If you want to use a generic default knob. It's essentually
a rectangle that fills the body of the proportional gadget. If you set
this flag, Intuition will initialize the rest of this structure.
A piece of code in the Example GAD.C shows where Three proportional
structures are initialized. These structures are named:
"r_prop", "g_prop", and "b_prop".
/***************************************************************************
Must Initialize the Proportional "Specialinfo" before
opening up the window. Init Flags, and position.
***************************************************************************/
r_prop.Flags = g_prop.Flags = b_prop.Flags = FREEHORIZ | AUTOKNOB;
r_prop.HorizBody = g_prop.HorizBody = b_prop.HorizBody = 0x1000;
r_prop.HorizPot = g_prop.HorizPot = b_prop.HorizPot = 0x8000;
FREEHORIZ - Set this flag if you only want the "slider" or "Pot" to
slide horizontally.
FREEVERT - Set this flag if you want to slide vertically only.
PROPBORDERLESS - Set this flag if you don't want borders.
KNOBHIT - Check this flag if you want to know if the mouse button is
on the knob.
For example, if you want a standard slider which is horizontally placed
in the window, set the flags: AUTOKNOB | FREEHORIZ
If you are using a custom gadget, for instance a "joystick" that can move
BOTH horizontally and vertically like the source code example in this lesson.
then set the flags: FREEHORIZ | FREEVERT.
-- (HorizPot) - Horizontal Position value for the gadget.
-- (VertPot) - Vert Position value for the gadget.
-- (horizBody) - The incremental width of the gadget. If set to 0x1000,
means that the pot will move 1/16th of the full position if the mouse
was pressed between the slider and the side of the gadget. it always
moves "towards" the point where the mouse was pressed. The "joystick"
custom gadget in the example sort of "Follows" the mouse.
-- (VertBody) - Vertical incremental width of the gadget.
The following fields are set by Intuition and are accessable to the
user if needed.
-- (cWidth) - Container width.
-- (cHeight) - Container height.
-- (HPotRes, VPotRes) - Horiz and Vert increments.
-- (LeftBorder, TopBorder) - Container borders.
Here is a PropInfo structure for a custom designed joystick.
struct PropInfo cust_prop = {
FREEHORIZ | FREEVERT, /* Want knob to go both vert and horiz */
0x8000, 0x8000, /* Want knob to be centered initially */
0x800, 0x800, /* Smallest increment the knob can move */
150, 50, /* cWidth, cHeight - Container w & h */
1, 1, /* HPosres, VPotres - Pot increments */
0, 0 /* Container borders */
};
You can stick this anywhere in the global declarations section of your
program. Because of the limitations of the Lattice C compiler, It should be
declared "Before" the Gadget structure that uses it.
An important thing to remember about constructing gadgets is that the
Coordinates in the Gadget structure are relative to the coordinates in the
Window or Screen.
The coordinates in the border, or intuitext structure used by gadgets are
RELATIVE to the Gadgets and NOT the window. For instance, if you want text
to be displayed OVER the gadget rectangle, your Y coords will be about -8 to
-10, while your x coords will be positive. The point where text is written
is at the UPPER LEFT section of the letters and NOT the lower left portion of
the letters like in the Macintosh.
If you use borders around your gadgets, make sure you make room for at least
one pixel around the "Selection box". Because, when the user presses in the
box, it is inversed, and if the border coincides with a pixel in the
selection box, that pixel overlaps and turns into another color, thus
making it look a bit cludgey.
HOW TO CREATE GADGETS IN YOUR PROGRAM
-------------------------------------
FIRST OFF - Sketch out an approximate picture showing approximately what the
overall layout of the gadgets should look like. Eventually, we will write a
Gadget Editor, but for now, lets make one up the old fashion way.
Define gadget structures for each gadget. Set the gadget flags
appropriately, specify pointers to Special structures, like "PropInfo" or
"StringInfo" structure in the "SpecialInfo" field. If you have custom images
that you have created, you need to declare a pointer to the image.
When you declare the gadgets, you create the LAST gadget first in your
Source code. Each sucessive gadget then "Links" to the one in front of it.
The last gadget pointer is a NULL. After each of the gadgets are linked
properly, then:
Declare any custom images, borders, or Text associated with the gadget.
This section of code shows an example of this. Remember, this portion of
code should come BEFORE any of the gadget declarations because the C compiler
doesn't seem to be able to forward reference.
/* Image for a custom proportional gadget */
UWORD custimage[] = {
0x0000, 0x0000, 0x0180, 0x0660, 0x1818, 0x2004, 0x4002, 0x4002,
0x4002, 0x4002, 0x2004, 0x1818, 0x0660, 0x0180, 0x0000, 0x0000
};
struct Image cus_image = {
0, 0, /* LeftEdge, TopEdge */
16, 16, 1, /* Width, Height, Depth */
&custimage[0], /* Pointer to bit image */
1, 0, /* PlanePick, Planeonoff */
NULL /* No other images */
};
One of the gadgets that use the above image:
#define CUST_KNOB 4
struct Gadget cust_knob = {
&tex_gad, 17, 140, 150, 50, GADGHCOMP, GADGIMMEDIATE | RELVERIFY,
PROPGADGET, (APTR)&cus_image, NL,
&cus2_txt, NL, (APTR)&cust_prop, CUST_KNOB, NL
};
Now, we have to make sure the very first gadget is linked to our window OR
SCREEN. In this particular example, we are only using a window, and are
using the Intuition WorkBench Screen. The NewWindow structure is declared
further down in the Code as shown below. Making the assumption that the
gadget shown above is the FIRST gadget (last in listing), then the New
Window structure is shown as below.
/***************************************************************************
* N E W W I N D O W S T R U C T U R E
***************************************************************************/
struct NewWindow nw = {
0, 0, /* Start position */
320, 200, /* width, height, */
0, 1, /* detail, block pens */
CLOSEWINDOW /* IDCMP flags */
| REFRESHWINDOW
| MOUSEBUTTONS
| MOUSEMOVE
| GADGETDOWN <-- MUST SET THIS ONE
| GADGETUP, <-- AND THIS ONE
/* Regular flags for gadgets and such */
WINDOWDEPTH
| WINDOWSIZING
| WINDOWDRAG
| REPORTMOUSE <-- AND THIS ONE
| WINDOWCLOSE
| SMART_REFRESH,
&cust_knob, /* First gadget in list <-- WE DO IT HERE */
NULL, /* User checkmark */
"Fun with Gadgets", /* Window Title */
NULL, /* Pointer to screen (Set later) */
NULL, /* Pointer to superbitmap */
0, 0, 320, 186, /* Ignored because not sizeable */
WBENCHSCREEN, /* Using the Workbench screen */
};
The example program given uses a different First Gadget.
The last thing you should do is set the appropriate flags. That is
shown above.
RESPONDING TO THOSE GADGETS
---------------------------
Last but not least, you need to be able to respond, read, or act on a
gadget. This is done by "Listening" to a gadget port. A particular bit
comes to you in a Message class field. You must recieve this "message" from
Intuition telling you that the user "clicked" the mouse in a particular
gadget. You don't know which one yet. But you snatch that "message" by
detecting a certain bit in the message.class field. You tuck this value away
for later use and "Reply" to the message, using the ReplyMsg function. We
keep doing this over and over until the user closes the window. This is
called an "Event loop".
/***************************************************************************
MAIN EVENT LOOP
***************************************************************************/
for (;;)
{
if (message = (struct IntuiMessage *)GetMsg(w->UserPort)) {
MessageClass = message->Class;
code = message->Code;
ReplyMsg(message);
switch (MessageClass) {
case GADGETUP :
case GADGETDOWN : do_gadgets(message, w);
break;
case CLOSEWINDOW : close_things();
exit(0);
break;
case MOUSEBUTTONS: break;
} /* Case */
} /* if */
} /* for */
} /* main */
In the Message, contains the Address of the gadget chosen by the user. You
pass the Message and the Window into a function called do_gadgets. This
function identifies the gadget, then acts on it in the appropriate way.
This function is listed below. I basically grab the address of the
particular structure, then look for that special private code that I
described to identify the gadget.
/***************************************************************************
HANDLE THE GADGETS
***************************************************************************/
do_gadgets (mes, win)
struct IntuiMessage *mes; /* Pointer to Message structure */
struct Window *win; /* And a window structure */
{
struct Gadget *igad; /* Ptr to gadget that Intuition found */
int gadgid; /* ID Code identifying which gadget */
ULONG val;
igad = (struct Gadget *) mes->IAddress; /* Ptr to a gadget */
gadgid = igad->GadgetID; /* My own personal code for this gad */
val = (ULONG)TexString.LongInt;
switch(gadgid) {
case GREEN_GADGET: break;
case BLUE_GADGET : break;
case TEX_GAD : printf("got here ...\n");
printf("val = %ld\n", val);
break;
}
}
As each gadget is identified, a CASE statement selects the appropriate action
to be taken depending on the gadget. In many cases, the SAME action is
usually performed on similar gadgets, but in the above example, I only
handle 3 gadgets. I could have exampled more, but Good ol Lattice C has a
nasty bug that won't let me use four cases without crashing. This is why it
takes so long to write programs on the Amiga. But thats the price for being
a pioneer.
Feel free to chop it up and hack it to death. So gotta work on Menus
tommorrow. Only have the Amiga for 5 more days. Next on my aggenda for
learning is:
Menus
Requestors
Sound
This is it for now. Have fun hacking, and I will be back with more later.
Feel free to ask me questions, and tell me your problems with gadgets so we
can solve them.
/**************************************************************************
* F U N W I T H G A D G E T S
*
***************************************************************************/
#include <exec/types.h>
#include <exec/nodes.h>
#include <exec/lists.h>
#include <exec/ports.h>
#include <exec/devices.h>
#include <devices/keymap.h>
#include <graphics/regions.h>
#include <graphics/copper.h>
#include <graphics/gels.h>
#include <graphics/gfxbase.h>
#include <graphics/gfx.h>
#include <graphics/clip.h>
#include <graphics/view.h>
#include <graphics/rastport.h>
#include <graphics/layers.h>
#include <intuition/intuition.h>
#include <hardware/blit.h>
/***************************************************************************
IMPORTANT CONSTANTS
***************************************************************************/
unsigned int mask = 0; /* ONE BIT SET FOR EACH OPEN */
#define INTUITION 0x00000001
#define GRAPHICS 0x00000002
#define SCREEN 0x00000004
#define WINDOW 0x00000008
#define COLORMAP 0x00000010
#define MATH 0x00000020
#define MATHTRANS 0x00000040
#define NL 0
/***************************************************************************
* I N T U I T I O N G L O B A L V A R S
***************************************************************************/
struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;
struct IntuiMessage *message;
struct RastPort *rp;
struct Window *w;
/***************************************************************************
G A D G E T S L I V E H E R E
***************************************************************************/
/* Image for a custom proportional gadget */
UWORD custimage[] = {
0x0000, 0x0000, 0x0180, 0x0660, 0x1818, 0x2004, 0x4002, 0x4002,
0x4002, 0x4002, 0x2004, 0x1818, 0x0660, 0x0180, 0x0000, 0x0000
};
struct Image cus_image = {
0, 0, /* LeftEdge, TopEdge */
16, 16, 1, /* Width, Height, Depth */
&custimage[0], /* Pointer to bit image */
1, 0, /* PlanePick, Planeonoff */
NULL /* No other images */
};
struct IntuiText rtxt = {2,2,JAM1,-9,2,NL,(UBYTE *)"R",NL};
struct IntuiText gtxt = {2,2,JAM1,-9,2,NL,(UBYTE *)"G",NL};
struct IntuiText btxt = {2,2,JAM1,-9,2,NL,(UBYTE *)"B",NL};
struct IntuiText ntext = {2,2,JAM1, 10, -11, NL,
(UBYTE *) "Number entry", NL};
struct IntuiText cus_text = {2,2,JAM1, 2, -11, NL,
(UBYTE *) "Custom Prop Gadget", NL};
struct IntuiText cus1_txt = {2,2,JAM1, 161, 23, NL,
(UBYTE *) "Vert side", &cus_text };
struct IntuiText cus2_txt = {2,2,JAM1, 20, 50, NL,
(UBYTE *) "Hor side", &cus1_txt };
struct IntuiText bool_str = {2,2,JAM1, 4, 1, NL,
(UBYTE *) "START", NL };
struct IntuiText bool2_str = {2,2,JAM1, 9, 1, NL,
(UBYTE *) "STOP", NL };
struct Image r_img, g_img, b_img;
struct PropInfo r_prop,g_prop,b_prop;
struct PropInfo cust_prop = {
FREEHORIZ | FREEVERT, /* Want knob to go both vert and horiz */
0x8000, 0x8000, /* Want knob to be centered initially */
0x800, 0x800, /* Smallest increment the knob can move */
150, 50, /* cWidth, cHeight - Container w & h */
1, 1, /* HPosres, VPotres - Pot increments */
0, 0 /* Container borders */
};
#define STRINGSIZE 512
UBYTE DefString[STRINGSIZE] = "000000000000";
UBYTE Undo [STRINGSIZE];
struct StringInfo TexString = {
DefString, /* Buffer - Pointer to Buffer */
Undo, /* UndoBuffer - Undo buf ptr */
0, /* BufferPos - Init Chr Posn */
STRINGSIZE, /* MaxChars - Max number of Chars */
0, 0, /* DispPos - First Disp Chr */
13, /* NumChars - Number of Characters */
0, 0, 0, /* Posn Vars calc by Intuition */
NULL, /* No pointer to Rasport */
0, /* Longint Value */
NULL /* No pointer to alt Keyboard */
};
USHORT Pairs[] = {
-1, -1, /* Information describing the */
160, -1, /* border around the gadget */
160, 9,
-1, 9,
-1, -1
};
USHORT Pairs1[] = {
0, 0,
51, 0,
51, 11,
0, 11,
0, 0
};
#define NUM_PAIRS 5 /* There are Four pairs above */
struct Border StrBorder = {
-1, -1, /* LeftEdge, TopEdge */
1, 0, JAM1, /* FrontPen, BackPen DrawMode */
NUM_PAIRS, /* Number of XY Pairs */
(APTR)&Pairs, /* XY, Pointer to XY Pairs */
NULL /* No more borders */
};
struct Border butt_border = {
-1, -1,
1, 0, JAM1,
NUM_PAIRS,
(APTR)&Pairs1,
NULL
};
#define BLUE_GADGET 0
struct Gadget blue_gad = {
NL, 17,112, 150,11, GADGHCOMP, GADGIMMEDIATE | RELVERIFY,
PROPGADGET,(APTR)&b_img, NL,
&btxt, NL,(APTR)&b_prop, BLUE_GADGET, NL
};
#define GREEN_GADGET 1 /* Another personal ID */
struct Gadget green_gad = {
&blue_gad, 17,97, 120,11, GADGHCOMP, GADGIMMEDIATE | RELVERIFY,
PROPGADGET,(APTR)&g_img, NL,
>xt, NL,(APTR)&g_prop, GREEN_GADGET, NL
};
#define RED_GADGET 2 /* And yet another gadget */
struct Gadget red_gad = {
&green_gad, 17,82, 90,11, GADGHCOMP, GADGIMMEDIATE | RELVERIFY,
PROPGADGET,(APTR)&r_img, NL,
&rtxt, NL,(APTR)&r_prop, RED_GADGET, NL
};
#define TEX_GAD 3
struct Gadget tex_gad = {
&red_gad, 30, 30, 150,11, GADGHCOMP, STRINGCENTER | LONGINT | RELVERIFY,
STRGADGET, (APTR)&StrBorder, NL,
&ntext, NL, (APTR)&TexString, TEX_GAD, NL
};
#define CUST_KNOB 4
struct Gadget cust_knob = {
&tex_gad, 17, 140, 150, 50, GADGHCOMP, GADGIMMEDIATE | RELVERIFY,
PROPGADGET, (APTR)&cus_image, NL,
&cus2_txt, NL, (APTR)&cust_prop, CUST_KNOB, NL
};
#define BOOL_GAD1 5
struct Gadget bool_gad = {
&cust_knob, 30, 46, 50, 10, GADGHCOMP, GADGIMMEDIATE | RELVERIFY,
BOOLGADGET, (APTR)&butt_border, NL,
&bool_str, NL, NL, BOOL_GAD1, NL
};
#define BOOL_GAD2 6
struct Gadget bool2_gad = {
&bool_gad, 30, 60, 50, 10, GADGHCOMP, GADGIMMEDIATE | RELVERIFY,
BOOLGADGET, (APTR)&butt_border, NL,
&bool2_str, NL, NL, BOOL_GAD2, NL
};
/***************************************************************************
* N E W W I N D O W S T R U C T U R E
***************************************************************************/
struct NewWindow nw = {
0, 0, /* Start position */
320, 200, /* width, height, */
0, 1, /* detail, block pens */
CLOSEWINDOW /* IDCMP flags */
| REFRESHWINDOW
| MOUSEBUTTONS
| MOUSEMOVE
| GADGETDOWN
| GADGETUP,
/* Regular flags for gadgets and such */
WINDOWDEPTH
| WINDOWSIZING
| WINDOWDRAG
| REPORTMOUSE
| WINDOWCLOSE
| SMART_REFRESH,
&bool2_gad, /* First gadget in list */
NULL, /* User checkmark */
"Fun with Gadgets", /* Window Title */
NULL, /* Pointer to screen (Set later) */
NULL, /* Pointer to superbitmap */
0, 0, 320, 186, /* Ignored because not sizeable */
WBENCHSCREEN, /* Using the Workbench screen */
};
/***************************************************************************
M A I N P R O G R A M M O D U L E
***************************************************************************/
main()
{
ULONG MessageClass;
USHORT code;
int good_boy = FALSE; /* Be a "Bad boy", and hog the system **/
/***************************************************************************
Must Initialize the Proportional "Specialinfo" before
opening up the window. Init Flags, and position.
***************************************************************************/
r_prop.Flags = g_prop.Flags = b_prop.Flags = FREEHORIZ | AUTOKNOB;
r_prop.HorizBody = g_prop.HorizBody = b_prop.HorizBody = 0x1000;
r_prop.HorizPot = g_prop.HorizPot = b_prop.HorizPot = 0x8000;
/***************************************************************************
Read in the ligraries, and set each "read" mask bit.
***************************************************************************/
if(!(GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",0)))
{
printf("no graphics library!!!\n");
close_things();
exit(1);
}
mask |= GRAPHICS;
if(!(IntuitionBase = (struct IntuitionBase *)
OpenLibrary("intuition.library",0)))
{
printf("no intuition here!!\n");
close_things();
exit(2);
}
mask |= INTUITION;
/***************************************************************************
OPEN UP THE WINDOW ON TOP OF WORKBENCH SCREEN
***************************************************************************/
if (!(w = (struct Window *)OpenWindow(&nw) ))
{
printf("could not open the window\n");
close_things();
exit(3);
}
mask |= WINDOW;
/***************************************************************************
INITIALIZATION BEFORE ENTERING MAIN LOOP
***************************************************************************/
rp = w->RPort;
RefreshGadgets(&red_gad,w,NULL);
/***************************************************************************
MAIN EVENT LOOP
***************************************************************************/
for (;;)
{
if (message = (struct IntuiMessage *)GetMsg(w->UserPort)) {
MessageClass = message->Class;
code = message->Code;
ReplyMsg(message);
switch (MessageClass) {
case GADGETUP :
case GADGETDOWN : do_gadgets(message, w);
break;
case CLOSEWINDOW : close_things();
exit(0);
break;
case MOUSEBUTTONS: break;
} /* Case */
} /* if */
} /* for */
} /* main */
/***************************************************************************
HANDLE THE GADGETS
***************************************************************************/
do_gadgets (mes, win)
struct IntuiMessage *mes;
struct Window *win;
{
struct Gadget *igad; /* Ptr to gadget that Intuition found */
int gadgid; /* ID Code identifying which gadget */
ULONG val;
igad = (struct Gadget *) mes->IAddress; /* Ptr to a gadget */
gadgid = igad->GadgetID; /* My own personal code for this gad */
val = (ULONG)TexString.LongInt;
switch(gadgid) {
case GREEN_GADGET: break;
case BLUE_GADGET : break;
case TEX_GAD : printf("got here ...\n");
printf("val = %ld\n", val);
break;
}
}
/***************************************************************************
CLOSE EVERYTHING DOWN
***************************************************************************/
close_things()
{
if (mask & WINDOW) CloseWindow(w);
if (mask & GRAPHICS) CloseLibrary(GfxBase);
(void) OpenWorkBench();
if (mask & INTUITION) CloseLibrary(IntuitionBase);
}
To use this program, from CLI, type: gad > ser: Then connect serial
to a terminal or another computer. This sends the printf's thru the
serial port. Type numeric text in the text window above, and note the
output. You COULD just type GAD. It will output into the CLI window.
From dale@amiga.UUCP (Dale Luck) Thu Dec 12 22:34:18 1985
Relay-Version: version B 2.10.2 9/18/84; site gumby.UUCP
Posting-Version: version B 2.10.3 4.3bsd-beta 6/6/85; site amiga.amiga.UUCP
Path: gumby!uwvax!harvard!talcott!panda!genrad!decvax!decwrl!pyramid!amiga!dale
From: dale@amiga.UUCP (Dale Luck)
Newsgroups: net.micro.amiga
Subject: Re: Fun with gadgets
Message-ID: <394@amiga.amiga.UUCP>
Date: 13 Dec 85 04:34:18 GMT
Date-Received: 14 Dec 85 03:46:36 GMT
References: <338@well.UUCP>
Reply-To: dale@tooter.UUCP (Dale Luck)
Organization: Commodore-Amiga Inc., 983 University Ave #D, Los Gatos CA 95030
Lines: 31
In article <338@well.UUCP> crunch@well.UUCP (John Draper) writes:
>/***************************************************************************
> MAIN EVENT LOOP
>***************************************************************************/
>
> for (;;)
> {
>
> if (message = (struct IntuiMessage *)GetMsg(w->UserPort)) {
> MessageClass = message->Class;
> code = message->Code;
> ReplyMsg(message);
> switch (MessageClass) {
> } /* Case */
> } /* if */
> } /* for */
>} /* main */
>
This is similar to the loop I had in the dot.c program
If your program does need to do anything while waiting for
messages though you should use
for (;;)
{
Wait(1<<w->UserPort->mp_SigBit); /* wake up when message there */
if (message = (......
etc.
}
This will be much more fair to those other programs and to intuition
as well.
From jimm@amiga.UUCP (Jim Mackraz) Fri Dec 13 13:10:32 1985
Relay-Version: version B 2.10.2 9/18/84; site gumby.UUCP
Posting-Version: version B 2.10.3 4.3bsd-beta 6/6/85; site amiga.amiga.UUCP
Path: gumby!uwvax!harvard!talcott!panda!genrad!decvax!decwrl!pyramid!amiga!jimm
From: jimm@amiga.UUCP (Jim Mackraz)
Newsgroups: net.micro.amiga
Subject: IntuiCorrections to Draper and Luck examples
Message-ID: <397@amiga.amiga.UUCP>
Date: 13 Dec 85 19:10:32 GMT
Date-Received: 14 Dec 85 11:28:16 GMT
Reply-To: jimm@homer.UUCP (Jim Mackraz)
Organization: Commodore-Amiga Inc., 983 University Ave #D, Los Gatos CA 95030
Lines: 99
Hello net.micro.amiga, and thank you John Draper for forwarding the
cause of IntuiEducation. Dale Luck posted a comment on John's main
processing loop, but his correction itself was slightly in error.
Furthermore, John commits another common error in his example, duplicated
below.
EXAMPLE 1 ************ John D's example
for (;;)
{
if (message = (struct IntuiMessage *)GetMsg(w->UserPort)) {
MessageClass = message->Class;
code = message->Code;
ReplyMsg(message);
switch (MessageClass) {
case GADGETUP :
case GADGETDOWN : do_gadgets(message, w);
break;
case CLOSEWINDOW : close_things();
exit(0);
break;
case MOUSEBUTTONS: break;
} /* Case */
} /* if */
} /* for */
COMMENTS ********
As Dale pointed out, a polling loop on the message port is not a proper
multitasking way to behave. A more subtle error: note that the message is
replied to before its contents is used in do_gadgets(). A general principle
(metaphor by bobp) applies: A Message is a license to use a portion of the
sender's data space, which no longer applies after the message is Reply'd.
In this case, Intuition will reuse the message, its contents will change, and
do_gadgets() may be confused, or crashed, if this happens.
** IMPORTANT ****
I personally like the way John caches the code of the message, and replies as
soon as possible. This might prevent Intuition from allocating another
message for this window if it needs to send another, but the savings are
marginal. With the exception of the very dangerous MENUVERIFY, REQVERIFY,
and SIZEVERIFY messages, it doesn't really matter much if you Reply() before
or after you use the data in the message. HOWEVER, be careful about your
caching. In particular, IAddress is not guaranteed to hold a reasonable
value if it is not defined for the particular class of message.
So if you try to stash the Gadget ID
((struct Gadget *)message->IAddress)->GadgetID
at the same place John stashes the class and code, and if the class is not
GADGETUP or GADGETDOWN, you may get an address error (Guru Meditation
00000003.<your task here>). Check the Intuition Manual for the exact times
that IAddress is used and therefore guaranteed vaild.
EXAMPLE 2 ************ Dale's correction to busy loop
for (;;)
{
Wait(1<<w->UserPort->mp_SigBit); /* wake up when message there */
if (message = (......
etc.
}
COMMENTS *******
This demonstrates the spirit of the block-until-message approach, but makes a
subtle error: Messages queue, while Signals do not. Therefore, if two
messages arrive while you are in the body of the loop, when you Wait() you
will not sleep (signal has already been posted with the arrival of the
messages), but will process only one message. Next time you Wait(), you will
sleep although there is a message in the queue.
EXAMPLE 3 ************ What I use.
FOREVER /* define as for(;;) in intuition.h */
{
if ((msg = (struct IntuiMessage *)GetMsg(window->UserPort)) == NULL)
{
Wait(1<<window->UserPort->mp_SigBit);
continue;
}
...... etc. ...
}
COMMENTS ***** You may feel free to use any flow of control you like, of
course. I think I chose this one because it was different than the first
solution I saw.
GENERAL ***** I want to thank John again for his contributions. Unless I
missed something, the remainder of his posting was accurate and clear. I'm
the new guy at Amiga Software, and my responsibilities include maintenance
and enhancement of Intuition. I welcome all questions and suggestions and
comments. We have trouble mailing through ARPAnet gateways, so include your
phone number or USnail address, if you might want a direct reply.
It is my hope that I can also provide some examples for new Intuition and
Amiga application programmers, but time ..., you know.
{hplabs,decwr}!pyramid!amiga!jimm